package com.naiterui.ehp.bs.agent.service.impl;

import java.io.File;
import java.math.BigInteger;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import com.naiterui.common.redis.RedisUtil;
import com.naiterui.common.repository.page.PageParamVO;
import com.naiterui.common.repository.page.PageVO;
import com.naiterui.ehp.bp.constants.CommonConstant;
import com.naiterui.ehp.bp.support.exception.BaseExceptionCodes;
import com.naiterui.ehp.bp.support.exception.BusinessException;
import com.naiterui.ehp.bp.utils.date.DateUtil;
import com.naiterui.ehp.bp.utils.encypt.DESPlus;
import com.naiterui.ehp.bp.utils.encypt.DESUtil;
import com.naiterui.ehp.bp.utils.encypt.GengerCode;
import com.naiterui.ehp.bp.utils.encypt.MD5;
import com.naiterui.ehp.bp.utils.encypt.RSAUtil;
import com.naiterui.ehp.bp.utils.lang.ConfigUtil;
import com.naiterui.ehp.bp.utils.lang.StringUtil;
import com.naiterui.ehp.bs.agent.entity.AgAgent;
import com.naiterui.ehp.bs.agent.entity.AgAgentArea;
import com.naiterui.ehp.bs.agent.entity.AgAgentCustom;
import com.naiterui.ehp.bs.agent.entity.AgArea;
import com.naiterui.ehp.bs.agent.entity.AsAgentInviteCount;
import com.naiterui.ehp.bs.agent.exception.ExceptionCodes;
import com.naiterui.ehp.bs.agent.feign.IDoctorFeignClient;
import com.naiterui.ehp.bs.agent.po.AgentAuthPO;
import com.naiterui.ehp.bs.agent.repository.IAgAgentAreaRepository;
import com.naiterui.ehp.bs.agent.repository.IAgAgentCustomRepository;
import com.naiterui.ehp.bs.agent.repository.IAgAgentRepository;
import com.naiterui.ehp.bs.agent.repository.IAgAreaRepository;
import com.naiterui.ehp.bs.agent.repository.IAgCustomSummaryRepository;
import com.naiterui.ehp.bs.agent.repository.IAsAgentInviteCountRepository;
import com.naiterui.ehp.bs.agent.repository.IAsRecipelCountRepository;
import com.naiterui.ehp.bs.agent.service.IAgentService;
import com.naiterui.ehp.bs.agent.util.ConstantUtil;
import com.naiterui.ehp.bs.agent.util.ImgPathUtil;
import com.naiterui.ehp.bs.agent.util.RedisKeyUtil;
import com.naiterui.ehp.bs.agent.util.SMSUtil;
import com.naiterui.ehp.bs.agent.util.Tools;
import com.naiterui.ehp.bs.agent.vo.AgentAreaItemVO;
import com.naiterui.ehp.bs.agent.vo.AgentAuthInfoVO;
import com.naiterui.ehp.bs.agent.vo.AgentDetailVO;
import com.naiterui.ehp.bs.agent.vo.AgentItemVO;
import com.naiterui.ehp.bs.agent.vo.BaseInfoVO;
import com.naiterui.ehp.bs.agent.vo.CustomInviteParamVO;
import com.naiterui.ehp.bs.agent.vo.EntryAreaVO;
import com.naiterui.ehp.bs.agent.vo.UserVO;

import cn.hutool.core.util.IdcardUtil;
import lombok.extern.slf4j.Slf4j;

/**
 * @author yiren
 * @since 2022/2/16
 */
@Service
@Slf4j
public class AgentServiceImpl implements IAgentService {
	@Autowired
	private IAgAgentRepository agAgentRepository;

	@Autowired
	private IAgAreaRepository agAreaRepository;

	@Autowired
	private IAgAgentAreaRepository agAgentAreaRepository;
	@Autowired
	private IAgAgentCustomRepository agentCustomRepository;
	@Autowired
	private IAgCustomSummaryRepository agCustomSummaryRepository;
	@Autowired
	private IAsRecipelCountRepository asRecipelCountRepository;
	@Autowired
	private IAsAgentInviteCountRepository asAgentInviteCountRepository;

    @Autowired
    private IDoctorFeignClient doctorFeignClient;

	@Value("${file.base.prefix}")
	private String fileBasePrefix;

	@Override
	@Transactional(rollbackFor = Exception.class)
	public UserVO login(String phoneNum, String password, String code) throws BusinessException {
		AgAgent agAgent = null;
		Integer newRegister = 0;
		if (StringUtils.isNotEmpty(code)){
			// 短信验证码登录
			String redisKey = RedisKeyUtil.getCodeKey(phoneNum, RedisKeyUtil.CODE_KEY_TYPE_LOGIN);
			String redisCode = RedisUtil.valueOps().getString(redisKey);
			if (!code.equals(redisCode)){
				throw new BusinessException(BaseExceptionCodes.PARAM_ERROR, "验证码不正确");
			}
			agAgent = agAgentRepository.findByPhone(phoneNum);
			if (agAgent == null) {
				newRegister = 1;
				agAgent = new AgAgent();
                agAgent.setGender(0);
				agAgent.setPhone(phoneNum);
				agAgent.setSalt(GengerCode.generateSaltCode());
				agAgent.setStatus(AgAgent.STATUS_AUTH_NO);
				agAgent.setAccountStatus(AgAgent.ACCOUNT_STATUS_ON);
			}
		}else{
			// 密码登录
			agAgent = agAgentRepository.findByPhone(phoneNum);
			if (agAgent == null){
				throw new BusinessException(BaseExceptionCodes.PARAM_ERROR, "当前账号未注册");
			}
			if (StringUtils.isEmpty(agAgent.getPassword())){
				throw new BusinessException(BaseExceptionCodes.PARAM_ERROR, "用户名或密码错误，请重新输入");
			}
            String pwd;
			try {
				password = password.replaceAll(" ", "+");
				pwd = RSAUtil.decryptByPrivateKey(password);
			}catch (Exception e){
				throw new BusinessException(BaseExceptionCodes.PARAM_ERROR, "解密失败");
			}
            String salt = agAgent.getSalt();
            String md5Str = MD5.md5(pwd.trim() + salt);
			if (!md5Str.equals(agAgent.getPassword())){
                log.info("用户名或密码错误 pwd:{}, md5:{}, dbmd5:{}", (pwd + salt), md5Str, agAgent.getPassword());
				throw new BusinessException(BaseExceptionCodes.PARAM_ERROR, "用户名或密码错误，请重新输入");
			}
		}
		// agAgent.setToken(DESPlus.gengerateLoginToken(phoneNum + UUID.randomUUID()));
		agAgent.setToken(DESPlus.gengerateLoginToken(phoneNum));
		agAgentRepository.saveOrUpdate(agAgent);
		String redisKey = RedisKeyUtil.getLoginTokenKey(agAgent.getId());
		RedisUtil.valueOps().set(redisKey, agAgent.getToken());
		// 设置返回
		UserVO user = UserVO.of(agAgent);
		user.setNewRegister(newRegister);
		return user;
	}

    @Override
    public void logout(Long agentId, String token) throws BusinessException {

        AgAgent agAgent = Optional.ofNullable(agentId).map(id -> agAgentRepository.get(agentId)).orElse(null);
        if (agAgent == null) {
            log.warn("经纪人信息不存在。agentId:{}，token:{}", agentId, token);
            return;
        }

        String dbToken = agAgent.getToken();
        if (dbToken == null || "".equals(dbToken)) {
            log.warn("经纪人当前未登录。agentId:{},token:{}", agentId, token);
            return;
        }

        if (!dbToken.equals(token)) {
            throw new BusinessException(ExceptionCodes.HTTP_ERR);
        }

        // 4.清除数据库中token
        agAgent.setToken(null);
        agAgent.setChangedAt(new Timestamp(System.currentTimeMillis()));
        this.agAgentRepository.update(agAgent);

        // 清理医生登录TOKEN
        String redisKey = RedisKeyUtil.getLoginTokenKey(agAgent.getId());
        RedisUtil.keyOps().delete(redisKey);
    }

    @Override
    public void sendCode(String phoneNum, Integer type) throws BusinessException {
        // 1 手机号校验
        if (phoneNum == null || "".equals(phoneNum)) {
            log.info("{} 手机号为空", phoneNum);
            throw new BusinessException(ExceptionCodes.SMS_PHONE_NULL);
        }
        if (!StringUtil.isMobileNum(phoneNum)) {
            log.error("{} 不符合手机验证规则", phoneNum);
            throw new BusinessException(ExceptionCodes.SMS_PHONE_ERROR);
        }
        // 2 发送类型校验
        if (type == null) {
            throw new BusinessException(ExceptionCodes.SMS_PHONE_ACT_ERROR);
        }

        // 签名校验
        // Map<String, Object> signParams = new HashMap<>();
        // signParams.put("phoneNum", phoneNum);
        // signParams.put("actionType", actionType);
        // signParams.put("t", t);
        // boolean verify = SignatureVerifyUtil.verifySign(signParams, sign);
        // if (!verify) {
        // LOGGER.warn("签名校验失败signParams{}, sign:{}", signParams, sign);
        // throw new BusinessException(ExceptionCodes.SIGN_ERR);
        //
        String cacheKey = "";
        // 类型 (1:登录, 2:找回密码, 3:修改手机号)
        switch (type) {
            case 1:
                cacheKey = RedisKeyUtil.getCodeKey(phoneNum, RedisKeyUtil.CODE_KEY_TYPE_LOGIN);
                break;
            case 2:
                if (!this.existLogin(phoneNum)) {
                    throw new BusinessException(ExceptionCodes.AGENT_UNREGISTERED);
                }
                cacheKey = RedisKeyUtil.getCodeKey(phoneNum, RedisKeyUtil.CODE_KEY_TYPE_RESET_PWD);
                break;
            case 3:
                if (this.existLogin(phoneNum)) {
                    throw new BusinessException(ExceptionCodes.REGIST_EXSIT);
                }
                cacheKey = RedisKeyUtil.getCodeKey(phoneNum, RedisKeyUtil.CODE_KEY_TYPE_RESET_PHONE);
                break;
            default:
                log.error(" {}发送短信验证码不正确", type);
                throw new BusinessException(ExceptionCodes.SMS_PHONE_ACT_ERROR);
        }
        String code = null;
        if (RedisUtil.keyOps().existsKey(cacheKey)) {
            code = RedisUtil.valueOps().getString(cacheKey);
        }
        if (code == null) {
            code = GengerCode.generateSmsCode();
        }
        if (RedisUtil.keyOps().existsKey(RedisKeyUtil.PHONE_SEND_TIME_KEY + phoneNum)) {
            log.info("发送验证码两次间隔小于1分钟,电话为phoneNum=" + phoneNum);
            throw new BusinessException(ExceptionCodes.SMS_PHONE_MAX_FREQUENCY);
        }
        // 验证用户错误输入次数是否达到上限
        if (this.validUserOperatorFlag(cacheKey)) {
            log.info("发送验证码由于连续多次输入错误，账号暂时被锁定,电话为phoneNum=" + phoneNum);
            throw new BusinessException(ExceptionCodes.SMS_PHONE_VALID_MAX_COUNT);
        }
        // 验证码存放10分钟
        RedisUtil.valueOps().set(cacheKey, code, RedisKeyUtil.SAVE_VERIFY_CODE);
        // 验证码发送时间间隔
        // RedisUtil.keyOps().set(PropertyValueConstants.PHONE_SEND_TIME_KEY + phoneNum, "",
        // PropertyValueConstants.SEND_SPACE);
        RedisUtil.valueOps().set(RedisKeyUtil.PHONE_SEND_TIME_KEY + phoneNum, "", RedisKeyUtil.SEND_SPACE);
        // 统计当天发送量,如果发送key不存在，则删除以前统计量，否则在原统计量上激增
        if (!RedisUtil.keyOps().existsKey(RedisKeyUtil.PHONE_DAY_SEND_COUNT_KEY + phoneNum)) {
            RedisUtil.keyOps().delete(RedisKeyUtil.PHONE_SEND_COUNT_KEY + phoneNum);
            RedisUtil.valueOps().set(RedisKeyUtil.PHONE_DAY_SEND_COUNT_KEY + phoneNum, "", DateUtil.getDayOfSecond());
        }
        // 验证码发送总次数统计
        long count = RedisUtil.keyOps().incr(RedisKeyUtil.PHONE_SEND_COUNT_KEY + phoneNum);
        if (count > RedisKeyUtil.SEND_MAX_COUNT) {
            log.info("当天发送验证码次数已经超过10次，电话为phoneNum=" + phoneNum);
            throw new BusinessException(ExceptionCodes.SMS_PHONE_MAX_COUNT);
        }

        // 调用远程接口，发送验证码
        SMSUtil.Template tmpl = SMSUtil.Template.PWD;
        SMSUtil.sendSMS(phoneNum, tmpl, code);
    }

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void resetPwd(String phoneNum, String password, String code) throws BusinessException {
		// 校验短信验证码
		String redisKey = RedisKeyUtil.getCodeKey(phoneNum, RedisKeyUtil.CODE_KEY_TYPE_RESET_PWD);
		String redisCode = RedisUtil.valueOps().getString(redisKey);
		if (!code.equals(redisCode)){
			throw new BusinessException(BaseExceptionCodes.PARAM_ERROR, "验证码不正确");
		}
		// 解密密码
		String pwd = null;
		try {
			password = password.replaceAll(" ", "+");
            pwd = RSAUtil.decryptByPrivateKey(password);
		}catch (Exception e){
			throw new BusinessException(BaseExceptionCodes.PARAM_ERROR, "解密失败");
		}
		AgAgent agAgent = agAgentRepository.findByPhone(phoneNum);
		agAgent.setPassword(MD5.md5(pwd.trim()+agAgent.getSalt()));
		agAgentRepository.update(agAgent);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void resetPhone(Long agentId, String newPhoneNum, String code) throws BusinessException {
		// 校验短信验证码
		String redisKey = RedisKeyUtil.getCodeKey(newPhoneNum, RedisKeyUtil.CODE_KEY_TYPE_RESET_PHONE);
		String redisCode = RedisUtil.valueOps().getString(redisKey);
		if (!code.equals(redisCode)){
			throw new BusinessException(BaseExceptionCodes.PARAM_ERROR, "验证码不正确");
		}
		AgAgent agAgent = agAgentRepository.get(agentId);
		agAgent.setPhone(newPhoneNum);
		agAgentRepository.update(agAgent);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void resetHead(Long agentId, String headUrl) {
		AgAgent agAgent = agAgentRepository.get(agentId);
		agAgent.setHeadUrl(ImgPathUtil.urlToPath(headUrl));
		agAgentRepository.update(agAgent);
	}

	@Override
	public AgentAuthInfoVO getAuthInfo(Long agentId) throws BusinessException {
		AgAgent agAgent = agAgentRepository.get(agentId);
		if (agAgent == null){
			throw new BusinessException(BaseExceptionCodes.PARAM_ERROR);
		}
		AgentAuthInfoVO infoVO = new AgentAuthInfoVO();
		infoVO.setAgentId(agAgent.getId().toString());
		infoVO.setAgentName(Tools.nullToEmpty(agAgent.getName()));
		infoVO.setCardNo(Tools.nullToEmpty(agAgent.getCardNo()));
		infoVO.setFrontUrl(ImgPathUtil.pathToUrl(agAgent.getFrontUrl()));
		infoVO.setBackUrl(ImgPathUtil.pathToUrl(agAgent.getBackUrl()));

		List<AgAgentArea> agentAreaList = agAgentAreaRepository.findByAgentIdAndTitleTypeOrderById(agentId, AgAgentArea.TITLE_TYPE_AGENT);
		if (agentAreaList.size() > 0){
			AgAgentArea agentArea = agentAreaList.get(0);
			AgArea provinceArea = agAreaRepository.get(agentArea.getAreaId());
			if (provinceArea.getParentId() != null){
				AgArea area = agAreaRepository.get(provinceArea.getParentId());
				if (area != null) {
					infoVO.setAreaId(area.getId().toString());
					infoVO.setAreaName(area.getAreaName());
					infoVO.setProvinceAreaId(provinceArea.getId().toString());
					infoVO.setProvinceAreaName(provinceArea.getAreaName());
				}
			}

		}
		return infoVO;
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void saveAuthInfo(AgentAuthPO authPO) throws BusinessException {
		AgAgent agAgent = agAgentRepository.get(authPO.getAgentId());
		if (agAgent == null){
			throw new BusinessException(BaseExceptionCodes.PARAM_ERROR);
		}
		AgArea dbArea = agAreaRepository.get(authPO.getAreaId());
		if (dbArea == null || dbArea.getAreaLev() != AgArea.AREA_LEV_PROVINCE){
			throw new BusinessException(BaseExceptionCodes.PARAM_ERROR, "请选择省区");
		}
		if (!authPO.getCardNo().equals(agAgent.getCardNo())){
			long rowNum = agAgentRepository.countByCardNo(authPO.getCardNo());
			if (rowNum > 0){
				throw new BusinessException(BaseExceptionCodes.PARAM_ERROR, "身份信息已被注册");
			}
		}

        // 对姓名和身份证进行二要素验证
		try {
            doctorFeignClient.verifyIdCard(authPO.getCardNo(), authPO.getAgentName());
			agAgent.setGender(IdcardUtil.getGenderByIdCard(authPO.getCardNo()) == 1 ? 1 : 2);
		}catch (Exception e){
			throw new BusinessException(BaseExceptionCodes.PARAM_ERROR, "请确保姓名、身份证号为同一人");
		}

		agAgent.setName(authPO.getAgentName());
		agAgent.setBackUrl(ImgPathUtil.urlToPath(authPO.getBackUrl()));
		agAgent.setFrontUrl(ImgPathUtil.urlToPath(authPO.getFrontUrl()));
		agAgent.setCardNo(authPO.getCardNo());
		agAgent.setStatus(AgAgent.STATUS_AUTH_WAIT);
		agAgentRepository.update(agAgent);

		List<AgAgentArea> agentAreaList = agAgentAreaRepository.findByAgentIdAndTitleTypeOrderById(authPO.getAgentId(), AgAgentArea.TITLE_TYPE_AGENT);
		AgAgentArea saveArea = null;
		if (agentAreaList.size() > 0){
			saveArea = agentAreaList.get(0);
		}else{
			saveArea = new AgAgentArea();
			saveArea.setAgentId(authPO.getAgentId());
			saveArea.setAreaActive(AgAgentArea.AREA_ACTIVE_NO);
			saveArea.setTitleType(AgAgentArea.TITLE_TYPE_AGENT);
		}
		saveArea.setAreaId(authPO.getAreaId());
		saveArea.setAreaLev(dbArea.getAreaLev());
		saveArea.setCreatedAt(new Date());
		agAgentAreaRepository.saveOrUpdate(saveArea);
	}

	@Override
	public BaseInfoVO getBaseInfo(Long agentId) {
		AgAgent dbAgent = agAgentRepository.get(agentId);
		// 设置经纪人基本信息
		BaseInfoVO infoVO = new BaseInfoVO();
		infoVO.setAgentId(agentId);
		infoVO.setAgentName(dbAgent.getName());
		infoVO.setAgentPhone(dbAgent.getPhone());
		infoVO.setStatus(dbAgent.getStatus());
		infoVO.setHeadUrl(ImgPathUtil.pathToUrl(dbAgent.getHeadUrl()));
		if (dbAgent.getStatus() != AgAgent.STATUS_AUTH_YES) {
			return infoVO;
		}
		infoVO.setEntryTime(dbAgent.getEntryTime());
		// 设置经纪人入职区域信息
		List<AgAgentArea> dbAgentAreaList = agAgentAreaRepository.findByAgentIdOrderById(agentId);
		List<Long> areaIdList = dbAgentAreaList.stream().map(AgAgentArea::getAreaId).collect(Collectors.toList());
		Map<Long, AgArea> dbAgAreaMap = new HashMap<>();
		Iterable<AgArea> dbAreaList = agAreaRepository.findAllById(areaIdList);
		for (AgArea item : dbAreaList) {
			dbAgAreaMap.put(item.getId(), item);
		}
		List<AgentAreaItemVO> areaList = new ArrayList<>();
		AgentAreaItemVO activeItem = null;
		for (AgAgentArea item : dbAgentAreaList) {
			AgArea area = dbAgAreaMap.get(item.getAreaId());
			if (item.getTitleType() == AgAgentArea.TITLE_TYPE_AGENT){
				AgArea parentAreaItem = Optional.ofNullable(area.getParentId()).map(agAreaRepository::get).orElseGet(AgArea::new);
				infoVO.setEntryAreaVO(EntryAreaVO.builder()
						.areaId(parentAreaItem.getId()).areaName(parentAreaItem.getAreaName())
						.provinceAreaId(area.getId()).provinceAreaName(area.getAreaName())
						.build());
			}else{
				AgentAreaItemVO itemVO = new AgentAreaItemVO();
				itemVO.setAreaId(item.getAreaId());
				itemVO.setAreaLev(item.getAreaLev());
				itemVO.setAreaName(area.getAreaName());
				String parentAreaName = "";
				if (item.getAreaLev() == AgAgentArea.AREA_LEV_PROVINCE && area.getParentId() != null){
					AgArea parentAreaItem = agAreaRepository.get(area.getParentId());
					parentAreaName = parentAreaItem.getAreaName();
				}
				itemVO.setParentAreaName(parentAreaName);
				itemVO.setAreaActive(item.getAreaActive());
				if (item.getAreaActive() != null && item.getAreaActive() == AgAgentArea.AREA_ACTIVE_YSE) {
					activeItem = itemVO;
				}
				areaList.add(itemVO);
			}
		}
		if (activeItem == null && areaList.size() > 0) {
			// 如果没有选择经理区域，默认
			activeItem = areaList.get(0);
			activeItem.setAreaActive(AgAgentArea.AREA_ACTIVE_YSE);
		}
		infoVO.setAreaList(areaList);

		resetTitle(infoVO, activeItem);
		EntryAreaVO entryAreaVO = infoVO.getEntryAreaVO();
		String param = agentId+"::"+ entryAreaVO.getAreaId()+"::"+ entryAreaVO.getProvinceAreaId();
		// 设置邀请码
		infoVO.setInviteCode(DESUtil.desEncrypt(CommonConstant.AGENT_INVITE_CUSTOM_DES_SECRET, param));

		// 我的客户数
		AgAgentCustom queryCustom = new AgAgentCustom();
		queryCustom.setAgentId(agentId);
		infoVO.setMyCustomNum(agentCustomRepository.count(Example.of(queryCustom)));
		if (activeItem != null) {
			// 查询当前激活的省区ID
			List<Long> provinceAreaIdList = new ArrayList<>();
			provinceAreaIdList.add(activeItem.getAreaId());
			Set<Long> manageAgentIdSet = new HashSet<>();
			manageAgentIdSet.add(agentId);
			if (activeItem.getAreaLev() == AgAgentArea.AREA_LEV_REGION) {
				List<AgArea> dbProvinceAreaList = agAreaRepository.findByParentId(activeItem.getAreaId());
				provinceAreaIdList = dbProvinceAreaList.stream().map(AgArea::getId).collect(Collectors.toList());
				if (provinceAreaIdList != null && provinceAreaIdList.size() > 0){
					List<AgAgentArea> manageList = agAgentAreaRepository.findByAreaIdInAndTitleType(provinceAreaIdList, AgAgentArea.TITLE_TYPE_MANAGE);
					for (AgAgentArea item : manageList) {
						manageAgentIdSet.add(item.getAgentId());
					}
				}
			}
			if (provinceAreaIdList != null && provinceAreaIdList.size() > 0){
				// 下属经纪人总数
				long agentNum = agAgentAreaRepository.countAgentNum(provinceAreaIdList, manageAgentIdSet);
				infoVO.setAgentNumTotal(agentNum + manageAgentIdSet.size() -1);
				// 总下属客户数
				infoVO.setCustomNumTotal(agentCustomRepository.countByProvinceAreaIdIn(provinceAreaIdList));
			}

		}

		return infoVO;
	}

	private void resetTitle(BaseInfoVO infoVO, AgentAreaItemVO activeItem){
		int titleId = 0;
		String areaName = null;
		String parentAreaName = null;
		StringBuilder title = new StringBuilder();
		if (activeItem == null){
			EntryAreaVO vo = infoVO.getEntryAreaVO();
			areaName = vo.getProvinceAreaName();
			parentAreaName = vo.getAreaName();
		} else {
			titleId = activeItem.getAreaLev();
			areaName = activeItem.getAreaName();
			parentAreaName = activeItem.getParentAreaName();
		}
		title.append(ConstantUtil.titleTypeMap.get(titleId));
		title.append("(");
		if (StringUtils.isNotEmpty(parentAreaName)){
			title.append(parentAreaName).append("-");
		}
		title.append(areaName).append(")");
		infoVO.setTitleId(titleId);
		infoVO.setTitle(title.toString());
	}

	@Override
	public CustomInviteParamVO getInviteParam(Long agentId) throws BusinessException {
		AgAgent dbAgent = agAgentRepository.get(agentId);
		if (dbAgent == null){
			throw new BusinessException(BaseExceptionCodes.PARAM_ERROR);
		}
		if (dbAgent.getStatus() != AgAgent.STATUS_AUTH_YES){
			throw new BusinessException(BaseExceptionCodes.PARAM_ERROR, "经纪人未认证");
		}
		List<AgAgentArea> agentAreaList = agAgentAreaRepository.findByAgentIdAndTitleTypeOrderById(agentId, AgAgentArea.TITLE_TYPE_AGENT);
		// 已认证一定包含数据，并且一定是省级
		AgAgentArea agentArea = agentAreaList.get(0);
		AgArea dbArea = agAreaRepository.get(agentArea.getAreaId());
		return CustomInviteParamVO.builder().agentId(agentId).areaId(dbArea.getParentId()).provinceAreaId(dbArea.getId()).build();
	}

	@Override
	public AgentDetailVO getDetail(Long agentId) throws BusinessException {
		AgAgent dbAgent = agAgentRepository.get(agentId);
		if (dbAgent == null){
			throw new BusinessException(BaseExceptionCodes.PARAM_ERROR);
		}

		// 查询根据经纪人ID 汇总后的数据
		List<Object[]> customSummaryList = agCustomSummaryRepository.getTotalByAgentId(agentId);
		Object[] customSummary = customSummaryList.size() > 0 ? customSummaryList.get(0) : null;
		int recipelTotal = 0;
		int orderPriceTotal = 0;
		if (customSummary != null&& customSummary.length == 2){
			recipelTotal = customSummary[0]==null ? 0 : Integer.parseInt(customSummary[0].toString());
			orderPriceTotal = customSummary[1]==null ? 0 : Integer.parseInt(customSummary[1].toString());
		}
		AgentDetailVO detailVO = new AgentDetailVO();
		detailVO.setAgentId(dbAgent.getId());
		detailVO.setAgentName(dbAgent.getName());
		detailVO.setAgentPhone(dbAgent.getPhone());
		detailVO.setHeadUrl(ImgPathUtil.pathToUrl(dbAgent.getHeadUrl()));
		detailVO.setEntryTime(dbAgent.getEntryTime());
		if (dbAgent.getEntryTime() != null) {
			detailVO.setEntryTimestamp(dbAgent.getEntryTime().getTime());
        } else {
            detailVO.setEntryTimestamp(new Date().getTime());
		}
		// 查询经纪人客户数
		Map<Long, Integer> customTotalMap = getAgentCustomNum(Arrays.asList(agentId));
		detailVO.setCustomTotal(customTotalMap.get(agentId));
		detailVO.setPrescriptionTotal(recipelTotal);
		detailVO.setDrugAmount(orderPriceTotal);
		detailVO.setAgentTitle(getAgentHighTitle(Arrays.asList(agentId)).get(agentId));
		Date thisTime = DateUtil.addDays(new Date(), -1);
		SimpleDateFormat sdf = new SimpleDateFormat(DateUtil.DATE_FORMAT);
		// 查询昨日数据
		String generateDate = sdf.format(thisTime);
		List<Object[]> recipelCountList = asRecipelCountRepository.getTotalByAgentId(agentId, generateDate);
		Object[] recipelCount = recipelCountList.size() > 0 ? recipelCountList.get(0) : null;
		// 查询前日数据
		String prevGenerateDate = sdf.format(DateUtil.addDays(thisTime, -1));
		List<Object[]> prevRecipelCountList = asRecipelCountRepository.getTotalByAgentId(agentId, prevGenerateDate);
		Object[] prevRecipelCount = prevRecipelCountList.size() > 0 ? prevRecipelCountList.get(0) : null;
		setOrderPriceQoq(detailVO, recipelCount, prevRecipelCount);

		setRecipelQoq(detailVO, recipelCount, prevRecipelCount);

		setCustomQoq(detailVO, generateDate, prevGenerateDate);

		return detailVO;
	}

	/**
	 * 设置订单金额环比参数
	 * @param detailVO
	 * @param item
	 * @param prevItem
	 */
	private void setOrderPriceQoq(AgentDetailVO detailVO, Object[] item, Object[] prevItem){
		int orderPriceTotal = 0;
		if (item != null && item.length > 1) {
			orderPriceTotal = item[1] != null ? Integer.parseInt(item[1].toString()) : 0;
		}
		int prevOrderPriceTotal = 0;
		if (prevItem != null && prevItem.length > 1) {
			prevOrderPriceTotal = prevItem[1] != null ? Integer.parseInt(prevItem[1].toString()) : 0;
		}
		double drugAmountQoq = Tools.getQoq(orderPriceTotal, prevOrderPriceTotal).doubleValue();
		detailVO.setYesterdayDrugAmount(orderPriceTotal);
		detailVO.setYesterdayDrugAmountQoq(drugAmountQoq >= 0 ? "+" : "-");
		detailVO.setYesterdayDrugAmountQoqVal((drugAmountQoq >= 0 ? drugAmountQoq : -drugAmountQoq)+"%");
	}
	/**
	 * 设置处方环比参数
	 * @param detailVO
	 * @param item
	 * @param prevItem
	 */
	private void setRecipelQoq(AgentDetailVO detailVO, Object[] item, Object[] prevItem){
		int recipelTotal = 0;
		if (item != null && item.length > 1) {
			recipelTotal = item[0] != null ? Integer.parseInt(item[0].toString()) : 0;
		}
		int prevRecipelTotal = 0;
		if (prevItem != null && prevItem.length > 1) {
			prevRecipelTotal = prevItem[0] != null ? Integer.parseInt(prevItem[0].toString()) : 0;
		}
		double recipelQoq = Tools.getQoq(recipelTotal, prevRecipelTotal).doubleValue();
		detailVO.setYesterdayPrescriptionTotal(recipelTotal);
		detailVO.setYesterdayPrescriptionQoq(recipelQoq >= 0 ? "+" : "-");
		detailVO.setYesterdayPrescriptionQoqVal((recipelQoq >= 0 ? recipelQoq : -recipelQoq)+"%");
	}

	/**
	 * 设置新增客户环比参数
	 * @param detailVO
	 * @param generateDate
	 * @param prevGenerateDate
	 */
	private void setCustomQoq(AgentDetailVO detailVO, String generateDate, String prevGenerateDate){
		AsAgentInviteCount inviteCount = asAgentInviteCountRepository.findByAgentIdAndGenerateDate(detailVO.getAgentId(), generateDate);
		int customTotal = 0;
		if (inviteCount != null) {
			customTotal = inviteCount.getNewNumber();
		}
		AsAgentInviteCount prevInviteCount = asAgentInviteCountRepository.findByAgentIdAndGenerateDate(detailVO.getAgentId(), prevGenerateDate);
		int prevCustomTotal = 0;
		if (prevInviteCount != null) {
			prevCustomTotal = prevInviteCount.getNewNumber();
		}
		double customQoq = Tools.getQoq(customTotal, prevCustomTotal).doubleValue();
		detailVO.setYesterdayCustomTotal(customTotal);
		detailVO.setYesterdayCustomQoq(customQoq >= 0 ? "+" : "-");
		detailVO.setYesterdayCustomQoqVal((customQoq >= 0 ? customQoq : -customQoq)+"%");
	}

	@Override
	public PageVO<AgentItemVO> findAgentPage(PageParamVO pageParamVO, Long provinceAreaId) {
		List<AgAgentArea> manageList = agAgentAreaRepository.findByAreaIdAndTitleType(provinceAreaId, AgAgentArea.TITLE_TYPE_MANAGE);
		AgAgentArea manageAgentArea = manageList.size() > 0 ? manageList.get(0) : null;
		// 查询经理入职区域是否当前省份
		long manageAgentId = -1;
		if (manageAgentArea != null) {
			AgAgentArea dbAgent = agAgentAreaRepository.findByAgentIdAndTitleTypeOrderById(manageAgentArea.getAgentId(), AgAgentArea.TITLE_TYPE_AGENT).get(0);
			if (!dbAgent.getAreaId().equals(provinceAreaId)){
				manageAgentId = manageAgentArea.getAgentId();
			}
		}
		Sort sort = Sort.by(Sort.Direction.DESC, "createdAt");
		Date endTime = DateUtil.getStartTime(null).getTime();
		Page<AgAgentArea> dbPage = agAgentAreaRepository.findByAreaId(provinceAreaId, manageAgentId, endTime, pageParamVO.getPageable(sort));

		List<AgAgentArea> dataList = dbPage.getContent();
		List<Long> agentIdList = dataList.stream().map(AgAgentArea::getAgentId).collect(Collectors.toList());
		// 查询经纪人最高职称
		Map<Long, String> titleMap = getAgentHighTitle(agentIdList);
		Iterable<AgAgent> dbAgentList = agAgentRepository.findAllById(agentIdList);
		Map<Long, AgAgent> dbAgentMap = new HashMap<>();
		for (AgAgent item : dbAgentList) {
			dbAgentMap.put(item.getId(), item);
		}
		// 查询经纪人客户数
		Map<Long, Integer> customTotalMap = getAgentCustomNum(agentIdList);
		List<AgentItemVO> resultList = new ArrayList<>();
		for (AgAgentArea item : dataList) {
			Long agentId = item.getAgentId();
			resultList.add(AgentItemVO.of(dbAgentMap.get(agentId), titleMap.get(agentId), customTotalMap.get(agentId)));
		}
        return PageVO.newBuilder().pageNo(pageParamVO.getPage()).pageSize(pageParamVO.getNum())
				.totalCount((int)dbPage.getTotalElements()).result(resultList).build();
	}

	@Override
	public String uploadFile(Integer type, MultipartFile file) throws BusinessException {
		if (!ConstantUtil.fileTypeMap.containsKey(type)) {
			throw new BusinessException(BaseExceptionCodes.PARAM_ERROR);
		}
		String path ="/agent/images/"+ConstantUtil.fileTypeMap.get(type)+"/";
		String localPath = "/"+this.fileBasePrefix + path;
		File filePath = new File(localPath);
		if (!filePath.exists()) {
			filePath.mkdirs();
		}
		String fileName = UUID.randomUUID() + "." + file.getOriginalFilename().split("\\.")[1];
		try {
			FileUtils.copyInputStreamToFile(file.getInputStream(), new File(localPath + fileName));
		}catch (Exception e){
			log.error("文件上传异常", e);
			throw new BusinessException(BaseExceptionCodes.PARAM_ERROR, "文件上传失败");
		}
		return ConfigUtil.getString("ehp.domain.img")+path+fileName;
	}

	/**
	 * 查询经纪人客户数量
	 * @param agentIdList
	 * @return
	 */
	private Map<Long, Integer> getAgentCustomNum(List<Long> agentIdList){
		Map<Long, Integer> numMap = new HashMap<>();
		List<Object[]> customTotalList = asAgentInviteCountRepository.findSummaryByAgentId(agentIdList);
		for (Object[] item : customTotalList) {
			Long agentId = ((BigInteger) item[0]).longValue();
			numMap.put(agentId, Integer.valueOf(item[1].toString()));
		}
		return numMap;
	}
	/**
	 * 获取经纪人最高职称
	 * @param agentIds
	 * @return
	 */
	private Map<Long, String> getAgentHighTitle(List<Long> agentIds) {
		Map<Long, String> titleMap = new HashMap<>();
		List<AgAgentArea> dbList = agAgentAreaRepository.findByAgentIdInAndTitleTypeOrderById(agentIds, AgAgentArea.TITLE_TYPE_MANAGE);
		Map<Long, List<AgAgentArea>> dbMap = dbList.stream().collect(Collectors.groupingBy(AgAgentArea::getAgentId));
		for (Long agentId : agentIds) {
			int titleId = 0;
			List<AgAgentArea> dataList = dbMap.get(agentId);
			if (dataList != null && dataList.size() > 0) {
				for (AgAgentArea item : dataList) {
					titleId = item.getAreaLev();
					if (AgAgentArea.AREA_LEV_REGION == item.getAreaLev()) {
						break;
					}
				}
			}
			titleMap.put(agentId, ConstantUtil.titleTypeMap.get(titleId));
		}
		return titleMap;
	}

    private boolean existLogin(String phoneNum) {
        // 读库获取
        AgAgent agAgent = agAgentRepository.findByPhone(phoneNum);
        return agAgent == null ? false : true;
    }

    public boolean validUserOperatorFlag(String cacheKey) {
        // 根据业务cacheKey，计算出验证validCacheKey和validCacheKey
        String validCacheTimeKey = cacheKey + "|time";
        // 错误次数的记录已经过期，则直接返回false
        if (!RedisUtil.keyOps().existsKey(validCacheTimeKey)) {
            return false;
        }
        // 缓存中获取验证次数
        String validCacheCountKey = RedisKeyUtil.getSmsValidUserOperatorKey(cacheKey);
        String validCountStr = RedisUtil.valueOps().getString(validCacheCountKey);
        long validCount = 0;
        if (StringUtils.isNotEmpty(validCountStr)) {
            validCount = Long.parseLong(validCountStr);
        }
        // 缓存中获取可操作次数
        Object avlCountObj = RedisUtil.hashOps().hget(RedisKeyUtil.VALID_KEY, RedisKeyUtil.VALID_COUNT_FIELD);
        Integer avlCount = Integer.parseInt(avlCountObj == null ? "0" : String.valueOf(avlCountObj));
        if (avlCount == 0) {
            avlCount = RedisKeyUtil.DEFAULT_COUNT_FIELD;
        }
        log.info("短信验证码发送查询验证key：" + cacheKey + "验证错误次数：" + validCount + ",最大可输入的验证错误次数：" + avlCount);
        return validCount > avlCount;
    }
}
